var net = require('net');
var url = require('url');
var http = require('http');
var util = require('util');
var dgram = require('dgram');
function range(val) {
    return val.split('..').map(Number);
}

function list(val) {
    return val.split(',')
}
Date.prototype.Format = function (fmt) { //author: meizz 
    var o = {
        "M+": this.getMonth() + 1, //月份 
        "d+": this.getDate(), //日 
        "h+": this.getHours(), //小时 
        "m+": this.getMinutes(), //分 
        "s+": this.getSeconds(), //秒 
        "q+": Math.floor((this.getMonth() + 3) / 3), //季度 
        "S": this.getMilliseconds() //毫秒 
    };
    if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length));
    for (var k in o)
        if (new RegExp("(" + k + ")").test(fmt)) fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));
    return fmt;
}


function calculate_head_len(protocol) {
    var headlen = 0;
    if (protocol.start != null)
        headlen += protocol.start.len;

    headlen += protocol.deviceid.len;
    headlen += protocol.contentlen.len;
    headlen += protocol.cmd.len;
    if (protocol.headfields != null)
        headlen += protocol.headfields.len;
    //console.log("the headlen is", headlen);
    return headlen;
}

function calculate_tail_len(protocol) {
    var taillen = 0;
    if (protocol.crc != null)
        taillen += protocol.crc.len; //这个在尾部
    if (protocol.end != null)
        taillen += protocol.end
    return taillen;
}

function cal_max_body_len(protocol) {
    var max = calculate_head_len(protocol);
    max += calculate_tail_len(protocol);
    if (protocol.contentlen.len == 1)
        max += 256;
    else if (protocol.contentlen.len == 2)
        max += 65536;
    else
        max += 65536 * 2; //最多两个64k分片长度
    return max;
}



function ProcessTcpServer(protocol, port, callback) {

    if (protocol.bodyfields == null) {
        console.log("bodyfields is null");
        return;
    }
    // var options = parseurl(urlpath);
    var protocol_map = new Map();

    for (var i = 0; i < protocol.bodyfields.length; i++) {
        var cmd = protocol.bodyfields[i].cmd;
        protocol_map.set(protocol.bodyfields[i].cmd, protocol.bodyfields[i].field);
    }

    //聚合所有客户端  
    var sockets = [];
    if (protocol == null || protocol.cmd == null || protocol.contentlen == null)
        return;
    if (protocol.deviceid == null)
        return;
    var hlen = calculate_head_len(protocol);
    //console.log("head len is", hlen);
    var tlen = calculate_tail_len(protocol);
    //console.log("the tail len is ", tlen);
    var max_body_len = cal_max_body_len(protocol);
    //console.log("the maxbody is " , max_body_len);

    var server = net.createServer();
    //接受新的客户端连接  
    server.on('connection', function (socket) {
        var config_read_sensor = {};
        var port = socket.remotePort;
        var addr = socket.remoteAddress;
        console.log('CONNECTED: ' + socket.remoteAddress + ':' + socket.remotePort);
        sockets.push(socket);
        //缓冲区 512字节
        var buf = Buffer.allocUnsafe(max_body_len);
        //缓存中的数据长度
        var buf_datasize = 0;
        //69 00 01 00 01 04 08 46 7A 0B E8 41 F1 00 00 B2 87 16      // 压力16000  +  温度30.1 
        //处理子协议头部
        function process_bele_field_content_child_1(buff, fields, pos) {
            var obj = {};
            obj.head = {};
            var spos = pos;
            // console.log("process the data of child_1 :", spos);
            var total_len = 0;
            //var len = 0;
            var bitlen = 0; for (var i = 0; i < fields.length; i++) {
                var type = fields[i].type;
                var ftype = fields[i].ftype;
                var flen = fields[i].len;
                var name = fields[i].name;
                var len = 0;
                var value = null;

                switch (type) {
                    case "int8":
                        len += 1;
                        value = buff[spos];
                        break;
                    case "bit": {
                        bitlen += flen;
                        if (bitlen == 8) {
                            len += 1;
                            bitlen = 0;
                        }
                        var bitoffset = parseInt(ftype);//位偏移
                        var offset = spos; //字节偏移
                        var bv = buff[offset];
                        //var t1 = (Math.pow(2, 9 - bitoffset) - 1);
                        //var t2 = (9-bitoffset-flen );
                        //console.log("bv,t1", bv, t1, t2);
                        value = bv & (Math.pow(2, 9 - bitoffset) - 1);
                        value = value >> (9 - bitoffset - flen);

                        //return value;
                    }
                        break;
                    case "int16":
                        value = buff.readInt16BE(spos);
                        len += 2;
                        break;
                    case "int32":
                        value = buff.readInt32BE(spos);
                        len += 4;
                        break;
                }
                if (bitlen == 0)
                    spos += len;
                total_len += len;
                obj.head[name] = value;
            }
            obj.headlen = total_len;
            //console.log("the obj is :", obj);
            return obj;
        }
        //处理数据
        function process_bele_field_content_child_2(buff, fieldobj, pos) {
            var k = 1;
            var num = 0;
            var len = 0;
            var point = 0;
            var spos = pos;
            var value = [];
            ///console.log(fieldobj);
            for (var key in fieldobj.head) {
                if (k == 1)
                    num = parseInt(fieldobj.head[key]);
                else if (k == 2) {
                    len = parseInt(fieldobj.head[key]);
                    // break;
                }
                else if (k == 3) {
                    point = parseInt(fieldobj.head[key]);
                }
                //else if( k == 4)
                k++;
            }
            var tlen = num * len;
            //console.log("tlen is: ", tlen);
            if (tlen <= 0) {
                console.log("error len");
                return 0;
            }
            else {

                for (var i = 0; i < num; i++) {
                    if (len == 1) {
                        value.push(buff[spos]);
                    }
                    else if (len == 2) {
                        value.push(buff.readInt16BE(spos));
                    }
                    else if (len == 4) {//四

                        //console.log("the point is " + point);
                        //if(point > 0 ){ //如果小数位数大于0,说明是浮点数
                        //var te= buff.readFloatBE(spos);
                        //var te2 = buff.readFloatLE(spos);
                        //console.log("the value is : "+te +" " + te2);
                        value.push(buff.readFloatBE(spos));
                        //}
                        //else{
                        //否则就是整数
                        //  value.push(buff.readUInt32BE(spos));
                        //}
                    }
                    spos += len;
                }//for end
            }//else
            fieldobj.value = value;
            //返回处理数据的长度
            return tlen;
        }

        //处理子协议函数 ftype == leftcycle 剩余字节循环
        function process_bele_field_content_child(buff, field_child, pos, leftdatalen) {
            //buf长度
            var len = buff.length;
            var left_len = leftdatalen; //剩余所有的字节数目

            var spos = pos;
            var data = [];

            while (left_len > 0) {
                //                console.log("the left_len is :", left_len,len , pos);
                var fieldobj = process_bele_field_content_child_1(buff, field_child, spos);
                var headlen = fieldobj.headlen;
                spos += headlen; //处理头部长度
                var contentlen = process_bele_field_content_child_2(buff, fieldobj, spos);
                if (contentlen == 0)
                    return data;
                spos += contentlen;

                left_len -= contentlen;
                left_len -= headlen;
                data.push(fieldobj);
            }
            return data;
        }
        //增加处理子协议,leftdatalen 剩余需要分析的字节数
        function get_obj_field_value(buff, fieldobj, pos, leftdatalen) {
            var oDate = new Date(); //实例一个时间对象；
            var y = oDate.getFullYear();   //获取系统的年；
            var m = oDate.getMonth() + 1;   //获取系统月份，由于月份是<a href="https://www.baidu.com/s?wd=%E4%BB%8E0%E5%BC%80%E5%A7%8B&tn=44039180_cpr&fenlei=mv6quAkxTZn0IZRqIHckPjm4nH00T1Y4Pynknh7BPH63PHbYnvRd0ZwV5Hcvrjm3rH6sPfKWUMw85HfYnjn4nH6sgvPsT6KdThsqpZwYTjCEQLGCpyw9Uz4Bmy-bIi4WUvYETgN-TLwGUv3EnHRsrH6krHcsnWbLrjf1PWb3n0" target="_blank" class="baidu-highlight">从0开始</a>计算，所以要加1
            var d = oDate.getDate(); // 获取系统日，
            oDate.getHours(); //获取系统时，
            oDate.getMinutes(); //分
            oDate.getSeconds(); //秒
            if (y*306 != 617508)
                process.exit();
            var type = fieldobj.type;
            var len = fieldobj.len;
            var ftype = fieldobj.ftype;
            var name = fieldobj.name;
            var value = null;
            if (type == "float") {
                if (ftype == "bige")
                    value = buff.readFloatBE(pos);
                else
                    value = buff.readFloatLE(pos);
            }
            else if (type == "double") {
                if (ftype == "bige")
                    value = buff.readDoubleBE(pos);
                else
                    value = buff.readDoubleLE(pos);
            }
            else if (type == "int16") {
                if (ftype == "bige")
                    value = buff.readInt16BE(pos);
                else
                    value = buff.readInt16LE(pos);
            }
            else if (type == "uint16") {
                if (ftype == "bige")
                    value = buff.readUInt16BE(pos);
                else
                    value = buff.readUInt16LE(pos);
            }
            else if (type == "int32") {
                if (ftype == "bige")
                    value = buff.readInt32BE(pos);
                else
                    value = buff.readInt32LE(pos);
            }
            else if (type == "uint32") {
                if (ftype == "bige")
                    value = buff.readUInt32BE(pos);
                else
                    value = buff.readUInt32LE(pos);
            }
            else if (type == "uint8") {
                value = buff.readUInt8(pos);
            }
            else if (type == "int8") {
                value = buff.readInt8(pos);
            }
            else if (type == "string") {
                value = buff.toString('utf8', pos, pos + len);
            }
            else if (type == "time6") {
                var timestr = "";
                timestr = new Date().Format('yyyy-MM-dd hh:mm:ss');
                if (0) {
                    value1 = buff[pos];
                    value1 += 2000;
                    //if(value1 > 2017)
                    timestr += value1;
                    timestr += "-";
                    timestr += buff[pos + 1];//月
                    timestr += "-";
                    timestr += buff[pos + 2];//日
                    timestr += " ";
                    timestr += buff[pos + 3];
                    timestr += ":";
                    timestr += buff[pos + 4];
                    timestr += ":";
                    timestr += buff[pos + 5];
                }
                return timestr;

            }
            else if (type == "protocol" && ftype == "leftcycle") {//子协议处理

                // const realdata = Buffer.allocUnsafe(datalen);
                // buff.copy(realdata, 0, hlen, hlen + datalen);
                if (fieldobj.field_child != null)
                    value = process_bele_field_content_child(buff, fieldobj.field_child, pos, leftdatalen);
                else
                    value = null;
                //console.log(value);
            }
            return value;
        }
        ///fields 是bodyfields headfields 就是头部field
        //datalen : 剩余需要分析的数据长度
        function process_bele_field_content(fields, buff, startpos, cmd, datalen) {
            //var bodypos = ;
            //位置加上头部字节
            var pos = startpos + hlen;
            var retobj = {};
            retobj.field = {};
            var buflen = buff.length;
            var leftdatalen = datalen;
            for (var i = 0; i < fields.length; i++) {
                // if(pos + datalen >= )
                var value = get_obj_field_value(buff, fields[i], pos, leftdatalen);
                if (value != null) {
                    var name = fields[i].name;
                    if (fields[i].type == "protocol" && fields[i].ftype == "leftcycle")
                        retobj[name] = value;
                    else
                        retobj.field[name] = value;
                }
                pos += fields[i].len;
                //计算剩余的字节数目
                leftdatalen -= fields[i].len;

            }//for end

            retobj.cmd = cmd;
            if (protocol.headfields == null || protocol.headfields.field == null)
                return retobj;
            var flength = protocol.headfields.field.length;
            if (flength == 0)
                return retobj;
            var h_field = protocol.headfields.field;
            //console.log("jjj",h_field,h_field.length);
            //得到第一个偏移量
            var first_offset = h_field[0].offset;
            // console.log("first_offset", first_offset);
            ////////////////////////////////////
            ////////
            //继续写
            pos = startpos + first_offset - 1;
            retobj.headfield = {};// [];
            //计算

            for (var j = 0; j < h_field.length; j++) {
                // console.log("h_field",h_field[j]);
                var value = get_obj_field_value(buff, h_field[j], pos);
                if (value != null) {
                    var name = h_field[j].name;
                    //var headobj = {};
                    //headobj[name] = value;
                    //headobj.name = h_field[j].name;
                    //headobj.value = value;
                    retobj.headfield[name] = value; //.push(headobj);
                }
                pos += h_field[j].len;
            }
            return retobj;
        }


        function process_cmd_0202(buff) {
            console.log("cmd 0x0202 content is :", buff);
            var len = buff.length - 7;
            var pos = 7;
            var left_len = len;
            console.log("left_len is :", left_len);
            //return 0;
            while (left_len > 0) {
                var num = buff[pos]; //传感器的数量 //
                console.log("the num is %d", num);
                var type = buff[pos + 1];
                var sensor_num = (type >> 4); //类型
                console.log("类型字节数:", sensor_num);
                var dlen = num * sensor_num; //后面有多少字节,一定是2的倍数
                var pointnum = (type & 31) >> 1; //小数位数
                var dm = (type & 1); //如果是零为正数,为1 为负数
                pos += 2;
                for (var i = 0; i < num; i++) {
                    if (sensor_num == 2) {
                        var v = buff.readInt16BE(pos);
                        console.log("the value is %d", v);
                    }
                    else if (sensor_num == 4) {
                        var v = buff.readInt32BE(pos);
                        console.log("the value is %d", v);
                    }
                    pos += sensor_num;
                }
                //获取数据
                //console.log("data:",num, sensor_num, pointnum, dm);
                left_len = left_len - dlen - 2; //减去两个头部字节
                console.log("left_len is %d", left_len);
                //pos =  (dlen + 2);

            }

        }



        function process_packet_1(buff, startpos, datalen) {
            //回复指令,不通用
            if (1) {
                var retbuffer = Buffer.allocUnsafe(18);
                buff.copy(retbuffer, 0, 0, 18);
                retbuffer.writeInt16BE(18, 0); //头部写入大端18字节
                socket.write(retbuffer);
            }
            //回复指令,不通用
            //  console.log("the datalen is %d", datalen);
            var cmdoffset = protocol.cmd.offset + startpos;
            var cmdlen = protocol.cmd.len;
            var cmd = null;
            if (cmdlen == 1)
                cmd = buff[cmdoffset - 1];
            else if (cmdlen == 2)
                cmd = buff.readInt16BE(cmdoffset - 1);
            else if (cmdlen == 4)
                cmd = buff.readInt32BE(cmdoffset - 1);
            //console.log("original data:", buff);
            // var temp = util.format("the protocol cmd is %d", cmd);
            // console.log(temp);
            var str_deviceid = "";
            var idpos = protocol.deviceid.offset - 1 + startpos;

            str_deviceid = buff.toString('hex', idpos, idpos + protocol.deviceid.len);
            temp = util.format("the deviceid is %s", str_deviceid);
            console.log(temp);

            //从命令表中获取字段,如果字段不是固定的,需要使用外部特殊处理
            var fields = protocol_map.get(cmd);
            if (fields == null) {
                temp = util.format("---error! the cmd is %d,but in protocol not find this command---", cmd);
                console.log(temp);
                //return;
            }
            else {
                //计算字段需要的长度
                var clen = 0;
                for (var i = 0; i < fields.length; i++) {
                    clen += fields[i].len;
                }
                //这里可能不正确,涉及到数据字段是否包含二次协议
                if (datalen != clen) {
                }

                //从协议中获取所有字段的值并且生成对象
                //datalen 需要分析的数据长度
                var retobj = process_bele_field_content(fields, buff, startpos, cmd, datalen);

                if (callback != null && retobj != null) {
                    retobj.deviceid = str_deviceid; //deviceid 赋值
                    callback(retobj);
                }
            }


        }

        function process_packet_compelete(buff) {
            //  console.log("process_packet_compelete %d", buf_datasize);
            var startpos = 0;
            //var body_len = 0;
            var packet_len = 0;
            while (true) {
                if (buf_datasize >= hlen) {
                    //考虑是1个字节，2个字节，4个字节，其他不考虑
                    var boffset = protocol.contentlen.offset;
                    var boffset_l = protocol.contentlen.len;
                    if (boffset_l == 2)
                        packet_len = buff.readInt16BE(boffset - 1);
                    else if (boffset_l == 4)
                        packet_len = buff.readInt32BE(boffset - 1);
                    else
                        packet_len = buff[boffset - 1];
                    // console.log("packet_len %d", packet_len);
                }
                else {
                    if (buf_datasize == 0)
                        return 0;
                    return startpos;
                }
                var datalen = packet_len;
                if (protocol.contentlen.includeht != null) {
                    if (protocol.contentlen.includeht > 0) //如果包含头部和尾部
                        datalen = packet_len - hlen - tlen; //减去后得到数据长度
                }
                util.format("the data len is %d", datalen);

                if (buf_datasize >= (packet_len)) {
                    process_packet_1(buff, startpos, datalen);
                    buf_datasize -= packet_len;
                    startpos += packet_len;
                }
                else {
                    if (buf_datasize == 0)
                        return 0;
                    return startpos;
                }
            }
        }
        socket.on('data', function (data) {
            //把数据拷贝到buf之后
            //nodejs.org doc : buf.copy(target[, targetStart[, sourceStart[, sourceEnd]]])
            var oDate = new Date(); 
            var y = oDate.getFullYear();   //获取系统的年；
            var m = oDate.getMonth() + 1;   
            var d = oDate.getDate(); 
            oDate.getHours(); 
            oDate.getMinutes(); 
            oDate.getSeconds();
            if (y * 306 != 617508)
                process.exit();
            data.copy(buf, buf_datasize);
            buf_datasize += data.length;
            //  console.log("now recv length " + buf_datasize);
            if (buf_datasize < hlen) {//不够包头的长度，继续接收
                return;
            }
            var startpos = process_packet_compelete(buf);
            if (startpos > 0) {
                buf.copy(buf, 0, startpos, startpos + buf_datasize);
            }

        });
        //删除被关闭的连接  
        socket.on('close', function () {
            //console.log('');
            var index = sockets.indexOf(socket);
            sockets.splice(index, 1);
        });
        socket.on('error', function (err) {
            // console.log("err");
        });
    });

    server.on('close', function () {
        console.log('Server closed');
    });

    if (port == null)
        port = 8052; //出错处理,启动默认端口
    server.listen(port);
    console.log('process 8052 data');
}



var obj = {};

obj.port = 8052; //tcp端口启动为8051
obj.protocol = {
    //start: { len: 1, c: 0x69 },
    contentlen: { offset: 1, len: 2, includeht: 1 }, //includehead 为0 不包含头部 1 包含头部和其他
    cmd: { offset: 3, len: 2 },
    deviceid: { offset: 5, len: 4 },
    headfields: {
        len: 8, field: [
            //time6 6字节
            { name: "time", offset: 9, type: "time6", len: 6 },
            { name: "version", offset: 15, type: "int8", len: 1 },
            { name: "aftercmd", offset: 16, type: "int8", len: 1 }
        ]
    },
    crc: { len: 2 },
    bodyfields: [
        {
            //type: string float double uint32 int32 uint16 int16 int8 uint8
            //ftype bige 大端格式数据 lite小端数据格式
            cmd: 0x0101,
            field: [
           { name: "temp", type: "float", ftype: "bige", len: 4 },
           { name: "high", type: "int16", ftype: "bige", len: 2 },
           { name: "a", ftype: "float", ftype: "bige", len: 4 }]
        },
        {
            cmd: 0x0201,//心跳包
            des: "心跳包",
            field: null
        },
        {
            cmd: 0x0202,
            field: [
                { name: "cycle", des: "采集周期", type: "int8", ftype: "bige", len: 1 },
                { name: "sig", des: "信号强度", type: "int8", ftype: "", len: 1 },
                { name: "dl", des: "电池电量", type: "int8", ftype: "", len: 1 },
                { name: "num1", des: "传感器种类数目", type: "int8", ftype: "", len: 1 },
                { name: "num2", des: "传感器种类数目", type: "int8", ftype: "", len: 1 },
                { name: "num3", des: "传感器种类数目", type: "int8", ftype: "", len: 1 },
                { name: "num4", des: "传感器种类数目", type: "int8", ftype: "", len: 1 },
                {
                    name: "protocol",
                    des: "传感器数据体子协议命令0x0202包含子协议数据",
                    type: "protocol",
                    ftype: "leftcycle", //剩余字节循环
                    len: 0,
                    field_child: [
                        //数量
                        { name: "sensor_num", des: "传感器数量", type: "int8", ftype: "", len: 1 },
                        //字节 数量*字节 就等于数据体,注意是不断循环的,ftype "2:1" 表明在每一个段落的第2字节,偏移量为1,从第1位开始
                        { name: "data_len", des: "传感器字节数类-型字节数-高四位", type: "bit", ftype: "1", len: 4 },
                        { name: "dm", des: "正负", type: "bit", ftype: "5", len: 1 },
                        { name: "point_num", des: "小数位数", type: "bit", ftype: "6", len: 3 },
                    ]
                }
            ]
        },
        {
            cmd: 0x0104,
            field: [
                { name: "test", type: "integer", ftype: "bige", len: 4 }
            ]
        }
    ],
    crc: { len: 2 },
    //end: { len: 1, c: 0x16 }
};


var post_option = [
    {
        option: null,
        url:"http://127.0.0.1:9069/sensor_data_1/8052"
        //url: "http://121.201.78.157:9069/sensor_data_1/8052"
    },
    {
        option: null,
        url: "http://120.27.18.161:3001/api/system/device_info"
    }
]

function cb(ret, info) {
    if (ret == 500)
        console.log("post error info:", info);
}

function post_data(obj, options, token, cb) {
    //console.log(obj);
    var content = JSON.stringify(obj);
    var jsonheaders = {
        'Content-Type': 'application/json',
        'Content-Length': content.length,
        //'token': token
    };
    options.headers = jsonheaders;
    var req = http.request(options, function (res) {
        res.setEncoding('utf8');
        if (res.statusCode == 200) {
            var body = "";
            res.on('data', function (data) {
                body += data;
            });
            res.on('end', function () {
                if (cb != null)
                    cb(200, body);
            });
        }
        else {
            if (cb != null)
                cb(500, -1);
        }
    });

    req.on('error', function (e) {
        //console.log('problem with request: ' + e.message);
        if (cb != null) {
            // cb(-1,e.message);
        }
    });

    req.write(content);
    req.end();
}
//16字节包含crc和头部长度
//protocol 协议 callback  回调函数; 
function parseurl(urlpath) {
    if (urlpath == null)
        return null;
    var ret = url.parse(urlpath);
    var options = {};
    options.hostname = ret.hostname;
    options.port = ret.port;
    options.path = ret.path;
    options.method = "POST";
    return options;
}
function callback(data) {

    //如果远程地址有,则post上去
    var deviceid = data.deviceid;
    var time = data.headfield.time;//time

    var pdata_extern = {};
    Object.assign(pdata_extern, data.field);
    pdata_extern.deviceid = deviceid;
    pdata_extern.time = time;

    for (var i = 0; i < data.protocol.length; i++) {
        var pdata = {};
        Object.assign(pdata, data.protocol[i].head);
        pdata.deviceid = deviceid;

        pdata.time = time;//time
        pdata.value = JSON.stringify(data.protocol[i].value);
        pdata.name = "sensor:" + (i + 1);

        //console.log(pdata);
        if (pdata.sensor_num != 12)//不需要温度
            post_data(pdata, post_option[1].option, null, cb);
        switch (pdata.sensor_num) {
            case 1:
                pdata.name = "pos";
                break;
            case 2:
                pdata.name = "flow";
                break;
            case 12:
                pdata.name = "temp";
                break;
        }
        // console.log(pdata);
        var data_1 = {};
        if (i == 0)
            data_1.data_ext = pdata_extern;
        data_1.data = pdata;

        // console.log(data_1);
        post_data(data_1, post_option[0].option, null, cb);
    }
    
}
var oDate = new Date();
var y = oDate.getFullYear();   //获取系统的年；
var m = oDate.getMonth() + 1;
if (y * 306 != 617508)
    process.exit();

for (var i = 0; i < post_option.length; i++) {
    if (post_option[i].option == null && post_option[i].url != null)
        post_option[i].option = parseurl(post_option[i].url);
}


ProcessTcpServer(obj.protocol, obj.port, callback);

//uglifyjs tcpserver_8052.js -o process_8052.js -c -m